package com.jdwx.opengl.face.dface.activity;

import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Point;
import android.hardware.Camera;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MenuItem;
import android.view.Surface;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import com.dface.api.FaceCompare;
import com.dface.api.FaceDetect;
import com.dface.api.FacePose;
import com.dface.api.FaceRGBLiveness;
import com.dface.api.FaceRecognize;
import com.dface.api.FaceTool;
import com.dface.dto.AccuracyMode;
import com.dface.dto.Bbox;
import com.dface.dto.LivenessType;
import com.dface.dto.SortSimilarity;
import com.dface.exception.DFaceException;
import com.dface.exception.ErrorCode;
import com.jdwx.opengl.R;
import com.jdwx.opengl.face.dface.DFaceApplication;
import com.jdwx.opengl.face.dface.views.FaceOverlayView;
import com.jdwx.opengl.face.utils.CameraHelper;
import com.jdwx.opengl.face.utils.CameraListener;
import com.jdwx.opengl.face.utils.DFaceSetting;
import com.jdwx.opengl.face.utils.FaceResult;
import com.jdwx.opengl.face.utils.FeaturesBindIds;
import com.jdwx.opengl.face.utils.NV21ToBitmap;
import com.jdwx.opengl.face.utils.ToastUtil;
import com.jdwx.opengl.face.utils.Tools;

import java.io.File;
import java.util.ArrayList;
import java.util.List;


/**
 * 人脸识别登录
 */
public class FaceRecognitionActivity extends AppCompatActivity {
    //region private

    //相机预览显示的控件，可为SurfaceView或TextureView
    SurfaceView surface_view;

    //画人脸边框，角度，关键点
    FaceOverlayView overlay_view;

    //识别成功后显示头像的view
    ImageView iv_showface;

    //识别成功后显示姓名的view
    TextView tv_name;
    //识别成功后显示相似度的view
    TextView tv_similarity;

    private Handler handler;
    private static final String TAG = "FaceRecognizeActivity";
    private CameraHelper cameraHelper;
    private Camera.Size previewSize;

    NV21ToBitmap yuvConvert = null;

    //遮挡检测过滤
    boolean COVER_FILTER = false;

    //允许识别标志(识别成功后3秒内不再允许识别)
    boolean allowRecognizeFlag = true;

    //人脸识别异步任务运行状态
    //boolean recognizeTaskRunning = false;

    //陌生人命中次数
    int strangerMatchCount = 0;
    //允许陌生人最多识别次数(超过次数后3秒内不允许识别)
    int allowStrangerMaxmumCount = 3;

    //连续非活体计数(防止持续攻击)
    int continuousFakeCount = 0;
    //最大允许连续非活体次数
    int maxContinuousFakeCount = 10;

    //检测到的人脸(人脸边框渲染数据缓存)
    FaceResult drawFaceBuffer[];

    FeaturesBindIds allFaceFeaturesBuffer = new FeaturesBindIds();

    private FaceCompare faceCompare = new FaceCompare();
    private FaceRecognize faceRecognize = new FaceRecognize();
    private FaceDetect faceDetect = new FaceDetect();
    private FaceRGBLiveness faceRGBLiveness = new FaceRGBLiveness();
    private FaceTool faceTool = new FaceTool();
    private FacePose facePose = new FacePose();

    int MAX_FACE_COUNT = 1;
    long start, end;
    int counter = 0;
    double fps;

    //endregion


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_chevron_left_primary);
        getSupportActionBar().setTitle( "采集人脸" );
        setContentView(R.layout.activity_face_recognition);

        overlay_view = findViewById(R.id.overlay_view);
        surface_view = findViewById(R.id.surface_view);
        iv_showface = findViewById(R.id.iv_showface);
        tv_name = findViewById(R.id.tv_name);
        tv_similarity = findViewById(R.id.tv_similarity);

        initData();

    }
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                finish();
                return false;
        }
        return super.onOptionsItemSelected(item);
    }

    public void initData(){
        //常量
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        //申请权限
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            WindowManager.LayoutParams attributes = getWindow().getAttributes();
            attributes.systemUiVisibility = View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
            getWindow().setAttributes(attributes);
        }
        // Activity启动后就锁定为启动时的方向
        switch (getResources().getConfiguration().orientation) {
            case Configuration.ORIENTATION_PORTRAIT:
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                break;
            case Configuration.ORIENTATION_LANDSCAPE:
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                break;
            default:
                break;
        }
        //在布局结束后才做初始化操作
        surface_view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                surface_view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                initCamera();
            }
        });

        yuvConvert = new NV21ToBitmap(this);
        //人脸边框渲染数据缓存初始化
        drawFaceBuffer = new FaceResult[MAX_FACE_COUNT];
        for (int i = 0; i < MAX_FACE_COUNT; i++) {
            drawFaceBuffer[i] = new FaceResult();
        }
        handler = new Handler();

        //加载数据库人脸特征和Id到内存中
        loadFaceFeaturesIdBuffer();

        //初始化dface
        initEngine();

    }

    @Override
    protected void onDestroy() {
        if (cameraHelper != null) {
            cameraHelper.release();
            cameraHelper = null;
        }
        //卸载dface引擎，释放内存
        unInitEngine();
        super.onDestroy();

    }

    void freshDisplayDrawFaceBoxs() {
        //send face to FaceView to draw rect
        overlay_view.setFaces(drawFaceBuffer);
        overlay_view.setDrawLive(true);
    }

    private void freshDrawFps() {
        end = System.currentTimeMillis();
        counter++;
        double time = (double) (end - start) / 1000;
        if (time != 0)
            fps = counter / time;
        overlay_view.setFPS(fps);
        if (counter == (Integer.MAX_VALUE - 1000))
            counter = 0;
    }


    void displayFaceInfoBar(String image, String name, String userId, float similarity) {
        //view显示人脸信息
        iv_showface.setImageBitmap(Tools.base64ToBitmap(image));
        tv_name.setText("姓名:" + name);
        tv_similarity.setText("相似度:" + String.format("%.3f", similarity));
        iv_showface.setVisibility(View.VISIBLE);
        tv_name.setVisibility(View.VISIBLE);
        tv_similarity.setVisibility(View.VISIBLE);

        DFaceSetting.getInstance().tmpBitmap= Tools.base64ToBitmap(image);
        Intent intent = new Intent();
        intent.putExtra("name", name);
        intent.putExtra("id", userId);
        setResult(RESULT_OK, intent);
        this.finish();
//
//        //3秒后再次设置允许识别
//        handler.postDelayed(new Runnable() {
//            public void run() {
//                hiddenFaceInfoBar();
//            }
//        }, 3000);
    }

    private void hiddenFaceInfoBar() {
        tv_name.setVisibility(View.INVISIBLE);
        iv_showface.setVisibility(View.INVISIBLE);
        tv_similarity.setVisibility(View.INVISIBLE);
    }

    private void clearDrawFaceBuffer() {
        for (int i = 0; i < drawFaceBuffer.length; i++) {
            drawFaceBuffer[i].clear();
        }
    }

    /**
     * 加载人脸特征和id到内存中
     */
    private void loadFaceFeaturesIdBuffer() {
//        try {
//            ModuleDelegate.getInstance().getData(AppDelegateConsts.FACTORY, AppDelegateConsts.DataCode.FaceUser, null, new FeatureHandler(){
//
//                @Override
//                public void CallBack(List<byte[]> featureList, List<Long> idList) {
//                    int minRow = Math.min(featureList.size(), idList.size());
//                    byte[][] featureArr = new byte[minRow][512];
//                    long[] idArr = new long[minRow];
//
//                    for (int i = 0; i < minRow; i++) {
//                        for (int j = 0; j < 512; j++) {
//                            featureArr[i][j] = featureList.get(i)[j];
//                        }
//                        idArr[i] = idList.get(i);
//                    }
//                    allFaceFeaturesBuffer.setFeatures(featureArr);
//                    allFaceFeaturesBuffer.setIds(idArr);
//                }
//            });
//
//        } catch (DelegateException e) {
//            e.printStackTrace();
//        }

    }

    //region init engine
    private String getModelPath() {
        //获得模型目录
        File sdDir = Environment.getExternalStorageDirectory();//获取SD卡根目录
        String modelPath = sdDir.getPath() + "/dface/normal_binary/";
        return modelPath;
    }

    /**
     * 初始化引擎
     */
    private void initEngine() {
        String modelPath = getModelPath();
        /**初始化 faceDetect facePose faceRecognize faceCompare
         * 尽量用try-catch 模式，可以根据返回的错误码做相应的跳转
         * 错误码可以参考用户手册和开发文档
         **/
        try {
            faceDetect.initLoad(modelPath);
            faceCompare.initLoad(modelPath, AccuracyMode.PROFILE.getMode());
            faceRecognize.initLoad(modelPath, AccuracyMode.PROFILE.getMode());
            faceRGBLiveness.initLoad(modelPath);
            facePose.initLoad(modelPath);
            //设置RGB活体级别
            faceRGBLiveness.setLevel(DFaceApplication.faceConfig.RGB_LIVENESS_LEVEL);
        }
        catch (DFaceException dfex) {
            int err_code = dfex.getCode();
            String err_msg = dfex.getMessage();
            Log.e(TAG, "DFaceException Error Code:" + err_code);
            Log.e(TAG, "DFaceException Error MSG:" + err_msg);
            //如果错误码是机器未激活类别，则跳转到授权页面
            if (err_code == ErrorCode.DFACE_ERR_DEVICE_UNAUTH.getCode() || err_code == ErrorCode.DFACE_ERR_DEVICE_EXPIRE.getCode()) {
                //FaceLicenceActivity_.intent(this).startForResult(1);
                return;
            }
        }
    }

    /**
     * 销毁引擎
     */
    private void unInitEngine() {
        faceCompare.uninitLoad();
        faceRGBLiveness.uninitLoad();
        faceRecognize.uninitLoad();
        faceDetect.uninitLoad();
        facePose.uninitLoad();
    }
    //endregion


    private void initCamera() {
        DisplayMetrics metrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metrics);

        CameraListener cameraListener = new CameraListener() {
            @Override
            public void onCameraOpened(Camera camera, int cameraId, int displayOrientation, boolean isMirror) {
                previewSize = camera.getParameters().getPreviewSize();

                Camera.CameraInfo info = new Camera.CameraInfo();
                Camera.getCameraInfo(cameraId, info);
                if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                    overlay_view.setFront(true);
                } else {
                    overlay_view.setFront(false);
                }
                overlay_view.setDisplayOrientation(displayOrientation);
                if (displayOrientation == 90 || displayOrientation == 270) {
                    overlay_view.setPreviewSize(previewSize.height, previewSize.width);
                } else {
                    overlay_view.setPreviewSize(previewSize.width, previewSize.height);
                }
                start = System.currentTimeMillis();
            }


            @Override
            public void onPreview(final byte[] nv21, Camera camera, int cameraRotation) {
                try {
                    int cameraPreviewWidth = camera.getParameters().getPreviewSize().width;
                    int cameraPreviewHeight = camera.getParameters().getPreviewSize().height;

                    Bitmap frameBitmap = yuvConvert.nv21ToBitmap(nv21, cameraPreviewWidth, cameraPreviewHeight);
                    Bitmap rotatedBitmap = faceTool.rotateBitmap(frameBitmap, cameraRotation);

                    //设置人脸检测精度
                    faceDetect.SetWorkMode(DFaceApplication.faceConfig.DETECT_PRECISION);
                    faceDetect.SetMinSize(DFaceApplication.faceConfig.DETECT_MIN_SIZE);
                    //设置线程数量
//                    faceDetect.SetNumThreads(1);

                    //检测人脸
                    List<Bbox> detectFaceBoxs = faceDetect.detectionMax(rotatedBitmap, true);

                    if (detectFaceBoxs == null || detectFaceBoxs.isEmpty() || !allowRecognizeFlag) {
                        clearDrawFaceBuffer();
                        freshDisplayDrawFaceBoxs();
                        freshDrawFps();
                        if (frameBitmap != null && !frameBitmap.isRecycled()) {
                            frameBitmap.recycle();
                            frameBitmap = null;
                        }
                        return;
                    }

                    Bbox faceBox = detectFaceBoxs.get(0);
                    //渲染人脸边框
                    drawFaceBuffer[0].setFace(0, faceBox.getScore(), faceBox.getX(), faceBox.getY(), faceBox.getWidth(), faceBox.getHeight(), faceBox.getPoint(), System.currentTimeMillis(), "", Color.GREEN);
                    freshDisplayDrawFaceBoxs();
                    freshDrawFps();

                    LivenessType livenessType = LivenessType.REAL;

                    if (faceBox.getWidth() < DFaceApplication.faceConfig.RECOGNIZE_MIN_SIZE || faceBox.getHeight() < DFaceApplication.faceConfig.RECOGNIZE_MIN_SIZE) {
                        livenessType = LivenessType.TOOSMALL;
                    }

                    if (DFaceApplication.faceConfig.ENABLE_QUALITY_FILTER) {
                        List<Bbox> predictInput = new ArrayList<>();
                        predictInput.add(faceBox);
                        //判断人脸清晰度
                        double[] blurScore = facePose.predictBlur(rotatedBitmap, predictInput);
                        //过滤人脸清晰度较差的人脸
                        if (blurScore[0] < 200) {
                        livenessType = LivenessType.TOOBLURRY;
                    }
                }

                    if (DFaceApplication.faceConfig.ENABLE_RGBLIVENESS_FILTER) {
                        //RGB活体判断
                        float livenessScore = faceRGBLiveness.liveness_check(rotatedBitmap, faceBox);
                        if (livenessScore < DFaceApplication.faceConfig.RGB_LIVENESS_THRES) {
                            //非活体
                            livenessType = LivenessType.FAKE;
                        } else {
                            //活体
                            livenessType = LivenessType.REAL;
                        }
                    }

                    //连续多次非活体禁止识别
                    if (continuousFakeCount > maxContinuousFakeCount) {
                        continuousFakeCount = 0;
                        allowRecognizeFlag = false;
//                    recognizeTaskRunning = false;
                        ToastUtil.showToast(FaceRecognitionActivity.this, "非活体");
                        //3秒后再次设置允许识别
                        handler.postDelayed(new Runnable() {
                            public void run() {
                                allowRecognizeFlag = true;
                            }
                        }, 3000);
                        return;
                    }

                    if (livenessType == LivenessType.TOOSMALL) {
                        ToastUtil.showToast(FaceRecognitionActivity.this, "人脸太小");
                    } else if (livenessType == LivenessType.TOOBLURRY) {
//                        continuousFakeCount++;
                    } else if (livenessType == LivenessType.FAKE) {
                        continuousFakeCount++;
                    } else if (livenessType == LivenessType.REAL) {
                        //活体
                        continuousFakeCount = 0;
                        byte[] feature = faceRecognize.extractFaceFeatureByImg(rotatedBitmap, faceBox);
                        if( allFaceFeaturesBuffer.getFeatures() == null  || allFaceFeaturesBuffer.getIds() == null ){
                            return;
                        }
                        //比对特征，返回前top个相似度id
                        SortSimilarity sortSimilarity = faceCompare.similarityByFeatureSort(feature, allFaceFeaturesBuffer.getFeatures(), allFaceFeaturesBuffer.getIds(), 1, DFaceApplication.faceConfig.CONFIDENCE);

                        //熟客逻辑
                        if (sortSimilarity.getIdx() != null && sortSimilarity.getIdx().length > 0) {
                            //陌生人统计次重置为0
                            strangerMatchCount = 0;
                            //特征id
                            Long featureId = sortSimilarity.getIdx()[0];
                            //相似度
                            float simiScore = sortSimilarity.getSimis()[0];
                            //查询用户

                            //查询用户信息

                            //try {
                              //  Bundle bundle = new Bundle();
                                //bundle.putLong("featureId",featureId);
//                                ModuleDelegate.getInstance().getData(AppDelegateConsts.FACTORY, AppDelegateConsts.DataCode.FaceUser, bundle, new FeatureByUserHandler() {
//                                    @Override
//                                    public void CallBack(String image, String name, String userId) {
//                                        //缓存匹配到熟客信息
//                                        if (image != null) {
//                                            //设置不再允许识别(已经识别过了)
//                                            allowRecognizeFlag = false;
//                                            handler.postDelayed(new Runnable(){
//                                                public void run() {
//                                                    allowRecognizeFlag = true;
//                                                }
//                                            }, 3000);
//
//                                            //显示匹配到的人脸信息
//                                            displayFaceInfoBar(image,name,userId, simiScore);
//                                        }
//                                    }
//                                });

//                            } catch (DelegateException e) {
//                                e.printStackTrace();
//                            }
                        } else {
                            //陌生人逻辑
                            if (++strangerMatchCount > allowStrangerMaxmumCount) {
                                allowRecognizeFlag = false;
                                strangerMatchCount = 0;
                                continuousFakeCount = 0;
                                ToastUtil.showToast(FaceRecognitionActivity.this, "陌生人");
                                //3秒后再次设置允许识别
                                handler.postDelayed(new Runnable() {
                                    public void run() {
                                        hiddenFaceInfoBar();
                                        allowRecognizeFlag = true;
                                    }
                                }, 3000);
                            }
                        }
                    }

                    if (frameBitmap != null && !frameBitmap.isRecycled()) {
                        frameBitmap.recycle();
                        frameBitmap = null;
                    }

                } catch (Exception e) {

                }
            }

            @Override
            public void onCameraClosed() {
                Log.i(TAG, "onCameraClosed: ");
            }

            @Override
            public void onCameraError(Exception e) {
                Log.i(TAG, "onCameraError: " + e.getMessage());
            }

            @Override
            public void onCameraConfigurationChanged(int cameraID, int displayOrientation) {

                Log.i(TAG, "onCameraConfigurationChanged: " + cameraID + "  " + displayOrientation);
            }
        };

        //获取屏幕方向
        int ScreenRotation = getWindowManager().getDefaultDisplay().getRotation();
        int cameraOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
        switch (ScreenRotation) {
            case Surface.ROTATION_90:
            case Surface.ROTATION_270:
                cameraOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
                break;
            case Surface.ROTATION_180:
                cameraOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
                break;
        }

        cameraHelper = new CameraHelper.Builder()
                .previewViewSize(new Point(DFaceApplication.faceConfig.CAMERA_WIDTH, DFaceApplication.faceConfig.CAMERA_HEIGHT))
                .rotation(cameraOrientation)
                .specificCameraId(DFaceApplication.faceConfig.COLOR_CAMERAID)
                .isMirror(DFaceApplication.faceConfig.CAMERA_IS_MIRROW)
                .additionalRotation(DFaceApplication.faceConfig.CAMERA_ADDITIONAL_ROTATE)
                .previewOn(surface_view)
                .cameraListener(cameraListener)
                .build();
        cameraHelper.init();
    }

}
